from CommandWriter import *
from StateReader import *
#from ReadFlags import *
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.filedialog import asksaveasfilename
import operator

#Array of buttons, for quick access
gridButtons = []
#Command cache for clicking buttons, basically acts as a queue.
commandCache = []
#Our set of alive cells for the current generation
cellGrid = set()
#Current width in buttons
currentWidth = 51
#Current height in buttons
currentHeight = 25
#Time for keypress delay
currentTime = time.time()

#Panning shift values
xShift = 0
yShift = 0
newXShift = 0
newYShift = 0

class LifeLike():

	#Paused boolean for panning while playing
	#or while paused
	paused = True
	#Block boolean for telling the poll thread
	#that we've panned
	panBlock = False
	
	#Translates Python based coordinates to ACL2
	#based coordinates
	def pyToACL2Coord(self, x, y):
		xOffSet = (currentWidth-1)/2
		yOffSet = (currentHeight-1)/2
		return (int(x-xOffSet), int(-(y-yOffSet)))
		
	#Translates ACL2 based coordinates to Python
	#based coordinates
	def acl2ToPyCoord(self, x, y):
		xOffSet = (currentWidth-1)/2
		yOffSet = (currentHeight-1)/2
		return (int(x+xOffSet), int(-y+yOffSet))
		
	#set the color of a cell to white(on)
	def setButtonToWhite(self, x, y):
		if x < 0 or y < 0 or x >= len(gridButtons) or y >= len(gridButtons[x]):
			return
		button = gridButtons[x][y]
		button["bg"] = "WHITE"
		
	#set the color of a cell to black (off)
	def setButtonToBlack(self, x, y):
		if x < 0 or y < 0 or x >= len(gridButtons) or y >= len(gridButtons[x]):
			return
		button = gridButtons[x][y]
		button["bg"] = "BLACK"

	#Given the new set of coordinates, turn off
	#cells that died and turn on cells that were
	#born
	def handleACL2Coordinates(self, coords):
		#cellGrid is the set of cells currently alive,
		#according to python
		global cellGrid

		#convert ACL2 coordinates to python coordinates
		pyCoords = set()
		for coord in coords:
			pyCoords.add(self.acl2ToPyCoord(coord[0], coord[1]))
		
		deadCoords = cellGrid - pyCoords
		
		bornCoords = pyCoords - cellGrid
		
		for coord in deadCoords:
			x,y = coord
			self.setButtonToBlack(x+xShift,y+yShift)

		for coord in bornCoords:
			x,y = coord
			self.setButtonToWhite(x+xShift,y+yShift)

		cellGrid = pyCoords
			
	#set a cell to on when it was clicked in python
	def handlePythonCoordinate(self, x, y):
		coord = (x, y)
		
		if coord in cellGrid:
			cellGrid.remove(coord)
			self.setButtonToBlack(x+xShift, y+yShift)
		else:
			cellGrid.add(coord)
			self.setButtonToWhite(x+xShift, y+yShift)
			
	#write out to the command chache when the user presses a button
	def buttonPressed(self, text):
		commandCache.append(text)
		print(text)
		WriteCommand(commandCache)

	#special version of buttonPressed for grid cells since
	#they require including params as well
	def gridButtonPressed(self, x, y):
		x -= xShift
		y -= yShift
		
		coord = self.pyToACL2Coord(x, y)
		newX, newY = (coord)
		
		cell = (x, y)
		if cell in cellGrid:
			command = "set-cell " + str(newX) + " " + str(newY) + " false"
		else:
			command = "set-cell " + str(newX) + " " + str(newY) + " true"
		
		self.handlePythonCoordinate(x, y)
		
		commandCache.append(command)
		WriteCommand(commandCache)
	
	#Rewrite a clean Grid. Doesnt actually change
	#cellGrid, just the gui Grid
	def updateGui(self):
		global xShift
		global yShift
		for coord in cellGrid:
			x, y = (coord)
			self.setButtonToWhite(x+newXShift, y+newYShift)
		xShift = newXShift
		yShift = newYShift
	
	#Clean the Grid. Doesnt actually change
	#cellGrid, just the gui Grid
	def clearGui(self):
		for coord in cellGrid:
			x, y = (coord)
			self.setButtonToBlack(x+xShift, y+yShift)
	
	#The key pressed event handler
	def key(self, event):
		global xShift
		global yShift
		global newXShift
		global newYShift
		global currentTime
		
		if time.time() - currentTime < .1:
			return
		currentTime = time.time()
		
		if event.keysym == 'Right':
			newXShift = xShift + 1
		if event.keysym == 'Left':
			newXShift = xShift + -1
		if event.keysym == 'Up':
			newYShift = yShift + -1
		if event.keysym == 'Down':
			newYShift = yShift + 1
			
		self.panBlock = True
		
		#If we are paused, then we need to update ourselves.
		if self.paused == True:
			self.clearGui()
			self.updateGui()

	#Handles loading and saving images
	def handle_file_button_command(self, command_name):
		filename = ""
		
		if command_name == "save-img":
			filename = asksaveasfilename(title="Save Your Automaton", defaultextension = '.bmp', filetypes=[("Bitmaps", ".bmp")])
		else:
			filename = askopenfilename(title="Select an Automaton to Load", defaultextension = '.bmp', filetypes=[("Bitmaps", ".bmp")])

		print(filename)
		if filename != "":
			if command_name == "load-img":
				self.clearGui()
				global cellGrid
				global xShift
				global yShift
				global newXShift
				global newYShift
				xShift = 0
				yShift = 0
				newXShift = 0
				newYShift = 0
				cellGrid = set()
			self.buttonPressed(command_name + " " + filename)

	#Activates and Deactivates button for a more fluid user experience
	def pause_play_control(self, action):
		global playButton
		global pauseButton
		global saveButton
		global loadButton
		global ffButton

		#GUI Update to make sure that the action followed up.
		if action == "play":
			playButton.config(state = DISABLED)
			pauseButton.config(state = NORMAL)
			ffButton.config(state = NORMAL)
			saveButton.config(state = DISABLED)
			loadButton.config(state = DISABLED)
			self.paused = False
		elif action == "fast-forward":
			ffButton.config(state = DISABLED)
			playButton.config(state = NORMAL)
		else:
			playButton.config(state = NORMAL)
			pauseButton.config(state = DISABLED)
			ffButton.config(state = DISABLED)
			saveButton.config(state = NORMAL)
			loadButton.config(state = NORMAL)
			if action == "pause":
				self.paused = True

		self.buttonPressed(action) #Handle the action

	#The init method. Constructs our frame, buttons, and grid
	#and binds the key press listener.
	def __init__(self, root):
		frame = Frame(root)
		frame.pack(side=LEFT, expand=1)
		
		gridFrame = Frame(root)
		gridFrame.pack(side=RIGHT, expand=1)
		Grid.rowconfigure(frame,7,weight=1)
		Grid.columnconfigure(frame,0,weight=1)
		
		global playButton
		playButton = Button(frame, text="Play", command = lambda: self.pause_play_control("play"))
		playButton.grid(row=0, column=0, padx=5, pady=5)
		global pauseButton
		pauseButton = Button(frame, text="Pause", command = lambda: self.pause_play_control("pause"))
		pauseButton.grid(row=1, column=0, padx=5, pady=5)
		pauseButton.config(state = DISABLED)
		global ffButton 
		ffButton = Button(frame, text="Fast Forward", command = lambda: self.pause_play_control("fast-forward"))
		ffButton.grid(row=2, column=0, padx=5, pady=5)
		ffButton.config(state = DISABLED)
		global saveButton
		saveButton = Button(frame, text="Save", command = lambda: self.handle_file_button_command("save-img"))
		saveButton.grid(row=3, column=0, padx=5, pady=5)
		global loadButton
		loadButton = Button(frame, text="Load", command = lambda: self.handle_file_button_command("load-img"))
		loadButton.grid(row=4, column=0, padx=5, pady=5)
		
		print("Lanching lifelike grid!")
		for x in range(currentWidth):
			gridColumn = []
			for y in range(currentHeight):
				cellColumn = x
				cellRow = y
				button = Button(gridFrame, background="BLACK", command = lambda cellColumn=x, cellRow=y: self.gridButtonPressed(cellColumn, cellRow))
				button.grid(row=y, column=x, ipadx=3, sticky=N+S+E+W)
				gridColumn.append(button)
			gridButtons.append(gridColumn)
		
		
		frame.bind_all('<Key>', self.key)
111111111111111